package com.frp.lib.config;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.frp.lib.message.Message;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by hujianjun on 11/22 0022.
 */
public class ProxyModel {
    public static Map<String, Class<? extends ProxyDefine>> TypeMap = new HashMap<String, Class<? extends ProxyDefine>>();
    static {
        TypeMap.put("tcp", TcpProxyDefine.class);
        TypeMap.put("udp", UdpProxyDefine.class);
        TypeMap.put("http", HttpProxyDefine.class);
        TypeMap.put("https", HttpsProxyDefine.class);
        TypeMap.put("stcp", StcpProxyDefine.class);
    }

    public static Message.NewProxy packToMsg(ProxyDefine proxyDefine) {
        Message.NewProxy msg =  new Message.NewProxy();
        //base
        msg.setProxy_type(proxyDefine.type);
        msg.setProxy_name(proxyDefine.name);
        msg.setUse_encryption(proxyDefine.use_encryption);
        msg.setUse_compression(proxyDefine.use_compression);
        //remote port
        msg.setRemote_port(proxyDefine.remote_port);
        //http
        msg.setCustom_domains(proxyDefine.custom_domains);
        msg.setSubdomain(proxyDefine.sub_domain);
        msg.setLocations(proxyDefine.locations);
        msg.setHost_header_rewrite(proxyDefine.host_header_rewrite);
        msg.setHttp_user(proxyDefine.http_user);
        msg.setHttp_pwd(proxyDefine.http_pwd);
        //stcp
        msg.setSk(proxyDefine.sk);

        return msg;
    }

    public static ProxyDefine unpackFromMsg(Message.NewProxy msg) {
        Class<? extends ProxyDefine> clazz = TypeMap.get(msg.getProxy_type());
        if (null==clazz)
            throw new RuntimeException("can not find class for : " + msg.getProxy_type());

        try {
            ProxyDefine proxyDefine = clazz.newInstance();
            //base
            proxyDefine.type = msg.getProxy_type();
            proxyDefine.name = msg.getProxy_name();
            proxyDefine.use_encryption = msg.isUse_encryption();
            proxyDefine.use_compression = msg.isUse_compression();
            //remote port
            proxyDefine.remote_port = (int) msg.getRemote_port();
            //http
            proxyDefine.custom_domains = msg.getCustom_domains();
            proxyDefine.sub_domain = msg.getSubdomain();
            proxyDefine.locations = msg.getLocations();
            proxyDefine.host_header_rewrite = msg.getHost_header_rewrite();
            proxyDefine.http_user = msg.getHttp_user();
            proxyDefine.http_pwd = msg.getHttp_pwd();
            //stcp
            proxyDefine.sk = msg.getSk();

            return proxyDefine;
        } catch (InstantiationException e) {
            throw new RuntimeException("create instance error.", e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("create instance error.", e);
        }
    }

    public static boolean check(ProxyDefine proxyConf) {
        //todo check proxy config can allow
        //only on server to call
        return true;
    }

    public static class ProxyDefine {
        //base proxy info
        @JsonProperty("proxy_name")
        public String name;
        @JsonProperty("proxy_type")
        public String type = "tcp";
        public boolean use_encryption = false;
        public boolean use_compression = false;

        //bind info
        public String remote_addr;
        public int remote_port;

        //local service info
        public String local_ip;
        public int local_port;

        //domain info
        public String[] custom_domains;
        public String sub_domain;

        //plugin info
        public String plugin;
        public Map<String, String> pluginParams;

        //http info
        public String[] locations;
        public String host_header_rewrite;
        public String http_user;
        public String http_pwd;

        //stcp info
        public String role;
        public String sk;
        public String server_name;
        public String bind_addr;
        public int bind_port;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public boolean isUse_encryption() {
            return use_encryption;
        }

        public void setUse_encryption(boolean use_encryption) {
            this.use_encryption = use_encryption;
        }

        public boolean isUse_compression() {
            return use_compression;
        }

        public void setUse_compression(boolean use_compression) {
            this.use_compression = use_compression;
        }

        public String getRemote_addr() {
            return remote_addr;
        }

        public void setRemote_addr(String remote_addr) {
            this.remote_addr = remote_addr;
        }

        public int getRemote_port() {
            return remote_port;
        }

        public void setRemote_port(int remote_port) {
            this.remote_port = remote_port;
        }

        public String getLocal_ip() {
            return local_ip;
        }

        public void setLocal_ip(String local_ip) {
            this.local_ip = local_ip;
        }

        public int getLocal_port() {
            return local_port;
        }

        public void setLocal_port(int local_port) {
            this.local_port = local_port;
        }

        public String[] getCustom_domains() {
            return custom_domains;
        }

        public void setCustom_domains(String[] custom_domains) {
            this.custom_domains = custom_domains;
        }

        public String getSub_domain() {
            return sub_domain;
        }

        public void setSub_domain(String sub_domain) {
            this.sub_domain = sub_domain;
        }

        public String getPlugin() {
            return plugin;
        }

        public void setPlugin(String plugin) {
            this.plugin = plugin;
        }

        public Map<String, String> getPluginParams() {
            return pluginParams;
        }

        public void setPluginParams(Map<String, String> pluginParams) {
            this.pluginParams = pluginParams;
        }

        public String[] getLocations() {
            return locations;
        }

        public void setLocations(String[] locations) {
            this.locations = locations;
        }

        public String getHost_header_rewrite() {
            return host_header_rewrite;
        }

        public void setHost_header_rewrite(String host_header_rewrite) {
            this.host_header_rewrite = host_header_rewrite;
        }

        public String getHttp_user() {
            return http_user;
        }

        public void setHttp_user(String http_user) {
            this.http_user = http_user;
        }

        public String getHttp_pwd() {
            return http_pwd;
        }

        public void setHttp_pwd(String http_pwd) {
            this.http_pwd = http_pwd;
        }

        public String getRole() {
            return role;
        }

        public void setRole(String role) {
            this.role = role;
        }

        public String getSk() {
            return sk;
        }

        public void setSk(String sk) {
            this.sk = sk;
        }

        public String getServer_name() {
            return server_name;
        }

        public void setServer_name(String server_name) {
            this.server_name = server_name;
        }

        public String getBind_addr() {
            return bind_addr;
        }

        public void setBind_addr(String bind_addr) {
            this.bind_addr = bind_addr;
        }

        public int getBind_port() {
            return bind_port;
        }

        public void setBind_port(int bind_port) {
            this.bind_port = bind_port;
        }

        @Override
        public String toString() {
            return "ProxyDefine{" +
                    "name='" + name + '\'' +
                    ", type='" + type + '\'' +
                    ", use_encryption=" + use_encryption +
                    ", use_compression=" + use_compression +
                    ", remote_addr='" + remote_addr + '\'' +
                    ", remote_port=" + remote_port +
                    ", local_ip='" + local_ip + '\'' +
                    ", local_port=" + local_port +
                    ", custom_domains=" + Arrays.toString(custom_domains) +
                    ", sub_domain='" + sub_domain + '\'' +
                    ", plugin='" + plugin + '\'' +
                    ", pluginParams=" + pluginParams +
                    '}';
        }
    }

    public static class TcpProxyDefine extends ProxyDefine {

    }

    public static class UdpProxyDefine extends ProxyDefine {

    }

    public static class HttpProxyDefine extends ProxyDefine {

        @Override
        public String toString() {
            return "HttpProxyDefine{" +
                    "locations=" + Arrays.toString(locations) +
                    ", host_header_rewrite='" + host_header_rewrite + '\'' +
                    ", http_user='" + http_user + '\'' +
                    ", http_pwd='" + http_pwd + '\'' +
                    "} " + super.toString();
        }
    }

    public static class HttpsProxyDefine extends ProxyDefine {

    }

    public static class StcpProxyDefine extends ProxyDefine {

        @Override
        public String toString() {
            return "StcpProxyDefine{" +
                    "role='" + role + '\'' +
                    ", sk='" + sk + '\'' +
                    ", server_name='" + server_name + '\'' +
                    ", bind_addr='" + bind_addr + '\'' +
                    ", bind_port=" + bind_port +
                    "} " + super.toString();
        }
    }

}
